package com.chucang.shucang.usr.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chucang.shucang.common.base.constant.CommonConstant;
import com.chucang.shucang.common.base.constant.SecurityConstant;
import com.chucang.shucang.common.base.exception.FastException;
import com.chucang.shucang.common.base.redis.RedisUtil;
import com.chucang.shucang.common.base.service.impl.CrudServiceImpl;
import com.chucang.shucang.common.base.utils.OpsUtil;
import com.chucang.shucang.common.base.utils.R;
import com.chucang.shucang.common.mq.constant.RabbitConstant;
import com.chucang.shucang.common.mq.to.NFTPublishTO;
import com.chucang.shucang.usr.constant.UsrCacheConstant;
import com.chucang.shucang.usr.constant.UsrCommonConstant;
import com.chucang.shucang.usr.dao.UserWalletDao;
import com.chucang.shucang.usr.dto.UserWalletDTO;
import com.chucang.shucang.usr.entity.*;
import com.chucang.shucang.usr.feign.BacService;
import com.chucang.shucang.usr.feign.OmsService;
import com.chucang.shucang.usr.feign.TtpService;
import com.chucang.shucang.usr.feign.vo.*;
import com.chucang.shucang.usr.service.*;
import com.github.yitter.idgen.YitIdHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 用户钱包
 *
 * @author flitsneak flitsneak@gmail.com
 * @since 1.0.0 2022-10-22
 */
@Service
@RequiredArgsConstructor
public class UserWalletServiceImpl extends CrudServiceImpl<UserWalletDao, UserWalletEntity, UserWalletDTO> implements UserWalletService {
    private final UserBaseService userBaseService;
    private final UserBlindBoxHoldService userBlindBoxHoldService;
    private final RedisUtil redisUtil;
    private final OmsService omsService;
    private final BacService bacService;
    private final TtpService ttpService;
    private final UserBillRecordService userBillRecordService;
    private final UserCollectionHoldService userCollectionHoldService;
    private final RabbitTemplate rabbitTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean collectionOrderSuccess(CollectionOrderBaseResVO orderBaseResVO, Integer from) {
        String orderSn = orderBaseResVO.getOrderSn();
        BigDecimal orderAmount = orderBaseResVO.getOrderAmount();
        //修改订单状态
        if (from == UsrCommonConstant.FROM_ALI_PAY) {
            omsService.collectionOrderSuccessByAliPay(orderSn, SecurityConstant.FROM_IN);
        } else if (from == UsrCommonConstant.FROM_WALLET) {
            omsService.collectionOrderSuccessByWallet(orderSn, SecurityConstant.FROM_IN);
        }
        //生成账单保存
        UserBillRecordEntity userBillRecordEntity = new UserBillRecordEntity();
        long l = YitIdHelper.nextId();
        userBillRecordEntity.setId(l);
        userBillRecordEntity.setOrderSn(orderSn);
        userBillRecordEntity.setBillType(0);
        userBillRecordEntity.setUserId(orderBaseResVO.getUserId());
        long sub = orderBaseResVO.getUserId() % 1000000;
        String billSn = String.valueOf(l) + sub;
        userBillRecordEntity.setStatus(1);
        userBillRecordEntity.setBillSn(billSn);
        userBillRecordEntity.setAmount(orderAmount);
        userBillRecordService.save(userBillRecordEntity);

        //获取用户链地址
        UserBaseEntity byId = userBaseService.getById(orderBaseResVO.getUserId());
        if (orderBaseResVO.getOrderType() == 0) {
            //一级市场 订单分发 批量上链
            List<Integer> list = redisUtil.multiRPopPipeline(String.format(UsrCacheConstant.COLLECTION_SERIAL_NUMS, orderBaseResVO.getCollectionId()), orderBaseResVO.getOrderNum());
            CollectionOrderItemsVO collectionOrderItemsVO = new CollectionOrderItemsVO();
            collectionOrderItemsVO.setCollectionId(orderBaseResVO.getCollectionId());
            collectionOrderItemsVO.setOrderSn(orderSn);
            collectionOrderItemsVO.setSerialNums(list);
            collectionOrderItemsVO.setUserId(orderBaseResVO.getUserId());
            omsService.addCollectionOrderItems(collectionOrderItemsVO, SecurityConstant.FROM_IN);
            //更新藏品归属
            List<UserCollectionHoldEntity> lists = new ArrayList<>(16);
            for (Integer integer : list) {
                UserCollectionHoldEntity userCollectionHoldEntity = new UserCollectionHoldEntity();
                userCollectionHoldEntity.setCollectionId(orderBaseResVO.getCollectionId());
                userCollectionHoldEntity.setUserId(orderBaseResVO.getUserId());
                userCollectionHoldEntity.setSerialNum(integer);
                userCollectionHoldEntity.setSourceType(0);
                userCollectionHoldEntity.setPurchasePrice(orderAmount.divide(new BigDecimal(orderBaseResVO.getOrderNum()), 2, RoundingMode.HALF_EVEN));
                userCollectionHoldEntity.setId(YitIdHelper.nextId());
                userCollectionHoldEntity.setStatus(0);
                lists.add(userCollectionHoldEntity);
            }
            userCollectionHoldService.saveBatch(lists);

            lists.forEach(c -> {
                NFTPublishTO nftPublishTO = new NFTPublishTO();
                nftPublishTO
                        .setName(c.getSerialNum().toString())
                        .setUserId(c.getUserId())
                        .setSourceType(0)
                        .setRecipient(byId.getOffshoreAccount())
                        .setClass_id(CommonConstant.CLASS_ID_PREFIX + c.getCollectionId())
                        .setOperation_id(c.getId().toString());
                rabbitTemplate.convertAndSend(RabbitConstant.NFT_EXCHANGE, RabbitConstant.NFT_PUBLISH_NFT_KEY, nftPublishTO);
            });
            return true;
        } else if (orderBaseResVO.getOrderType() == 1) {
            //二级市场，更改所属权
            LambdaQueryWrapper<UserCollectionHoldEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserCollectionHoldEntity::getCollectionId, orderBaseResVO.getCollectionId())
                    .eq(UserCollectionHoldEntity::getSerialNum, orderBaseResVO.getSerialNum())
                    .eq(UserCollectionHoldEntity::getStatus, 0)
                    .select();
            UserCollectionHoldEntity serviceOne = userCollectionHoldService.getOne(wrapper);
            LambdaUpdateWrapper<UserCollectionHoldEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(UserCollectionHoldEntity::getId, serviceOne.getId())
                    .set(UserCollectionHoldEntity::getStatus, 2);
            userCollectionHoldService.update(lambdaUpdateWrapper);
            //先查自己是否曾经拥有过
            LambdaQueryWrapper<UserCollectionHoldEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper
                    .eq(UserCollectionHoldEntity::getCollectionId, orderBaseResVO.getCollectionId())
                    .eq(UserCollectionHoldEntity::getUserId, orderBaseResVO.getUserId())
                    .eq(UserCollectionHoldEntity::getSerialNum, orderBaseResVO.getSerialNum());
            UserCollectionHoldEntity one = userCollectionHoldService.getOne(lambdaQueryWrapper);
            if (Objects.isNull(one)) {
                UserCollectionHoldEntity userCollectionHoldEntity = new UserCollectionHoldEntity();
                userCollectionHoldEntity.setCollectionId(orderBaseResVO.getCollectionId());
                userCollectionHoldEntity.setSerialNum(orderBaseResVO.getSerialNum());
                userCollectionHoldEntity.setSourceType(0);
                userCollectionHoldEntity.setPurchasePrice(orderAmount);
                userCollectionHoldEntity.setUserId(orderBaseResVO.getUserId());
                userCollectionHoldService.save(userCollectionHoldEntity);
            } else {
                LambdaUpdateWrapper<UserCollectionHoldEntity> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(UserCollectionHoldEntity::getId, one.getId())
                        .set(UserCollectionHoldEntity::getStatus, 0);
                userCollectionHoldService.update(updateWrapper);
            }
            //钱包扣除手续费到账对方账户
            R<ConsignChargeVO> consignCharge = bacService.getConsignCharge();
            ConsignChargeVO chargeVO = OpsUtil.of(consignCharge)
                    .assertCode(CommonConstant.SUCCESS, e -> new FastException("获取费率信息异常！"))
                    .getData()
                    .get();

            BigDecimal charge = new BigDecimal(chargeVO.getChargeRate());
            //扣除费率
            BigDecimal chargeRate = charge.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN);
            //扣除手续金额
            BigDecimal chargeAmount = orderAmount.multiply(chargeRate);
            //钱包到手金额
            BigDecimal earn = orderAmount.subtract(chargeAmount);
            Long oneUserId = serviceOne.getUserId();
            LambdaQueryWrapper<UserWalletEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserWalletEntity::getUserId, oneUserId)
                    .select();
            UserWalletEntity walletEntity = this.getOne(queryWrapper);
            LambdaUpdateWrapper<UserWalletEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserWalletEntity::getId, walletEntity.getId())
                    .set(UserWalletEntity::getBalance, walletEntity.getBalance().add(earn));
            this.update(updateWrapper);
            //nft转赠
            NFTTransferReq nftTransferReq = new NFTTransferReq();
            nftTransferReq.setNft_id(serviceOne.getNftId());
            //原用户链地址
            UserBaseEntity before = userBaseService.getById(serviceOne.getUserId());
            nftTransferReq.setOwner(before.getOffshoreAccount());
            nftTransferReq.setRecipient(byId.getOffshoreAccount());
            nftTransferReq.setClass_id(CommonConstant.NFT_TRANSFER_PREFIX + orderBaseResVO.getCollectionId());
            nftTransferReq.setOperation_id(orderSn);
            ttpService.transferNFT(nftTransferReq);

            return true;
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean blindBoxOrderSuccess(BlindBoxOrderBaseResVO orderBaseResVO, Integer from) {
        BigDecimal orderAmount = orderBaseResVO.getOrderAmount();
        String orderSn = orderBaseResVO.getOrderSn();
        //修改订单状态
        if (from == UsrCommonConstant.FROM_ALI_PAY) {
            omsService.blindBoxOrderSuccessByAliPay(orderSn, SecurityConstant.FROM_IN);
        } else if (from == UsrCommonConstant.FROM_WALLET) {
            omsService.blindBoxOrderSuccessByWallet(orderSn, SecurityConstant.FROM_IN);
        }
        //生成账单保存
        UserBillRecordEntity userBillRecordEntity = new UserBillRecordEntity();
        long l = YitIdHelper.nextId();
        userBillRecordEntity.setId(l);
        userBillRecordEntity.setOrderSn(orderSn);
        userBillRecordEntity.setBillType(0);
        userBillRecordEntity.setUserId(orderBaseResVO.getUserId());
        long sub = orderBaseResVO.getUserId() % 1000000;
        String billSn = String.valueOf(l) + sub;
        userBillRecordEntity.setStatus(1);
        userBillRecordEntity.setBillSn(billSn);
        userBillRecordEntity.setAmount(orderAmount);
        userBillRecordService.save(userBillRecordEntity);

        if (orderBaseResVO.getOrderType() == 0) {
            //一级市场 查看商品数量 订单分发
            List<Integer> list = redisUtil.multiRPopPipeline(String.format(UsrCacheConstant.BLIND_BOX_SERIAL_NUMS, orderBaseResVO.getBbId()), orderBaseResVO.getOrderNum());
            BlindBoxOrderItemsVO blindBoxOrderItemsVO = new BlindBoxOrderItemsVO();
            blindBoxOrderItemsVO.setBbId(orderBaseResVO.getBbId());
            blindBoxOrderItemsVO.setOrderSn(orderSn);
            blindBoxOrderItemsVO.setSerialNums(list);
            blindBoxOrderItemsVO.setUserId(orderBaseResVO.getUserId());
            omsService.addBlindBoxOrderItems(blindBoxOrderItemsVO, SecurityConstant.FROM_IN);
            //更新盲盒归属
            List<UserBlindBoxHoldEntity> lists = new ArrayList<>(16);
            for (Integer integer : list) {
                UserBlindBoxHoldEntity userBlindBoxHoldEntity = new UserBlindBoxHoldEntity();
                userBlindBoxHoldEntity.setBbId(orderBaseResVO.getBbId());
                userBlindBoxHoldEntity.setUserId(orderBaseResVO.getUserId());
                userBlindBoxHoldEntity.setSerialNum(integer);
                userBlindBoxHoldEntity.setSourceType(0);
                userBlindBoxHoldEntity.setPurchasePrice(orderAmount.divide(new BigDecimal(orderBaseResVO.getOrderNum()), 2, RoundingMode.HALF_EVEN));
                userBlindBoxHoldEntity.setId(YitIdHelper.nextId());
                userBlindBoxHoldEntity.setStatus(0);
                lists.add(userBlindBoxHoldEntity);
            }
            userBlindBoxHoldService.saveBatch(lists);
            return true;
        } else if (orderBaseResVO.getOrderType() == 1) {
            //二级市场，更改所属权
            LambdaQueryWrapper<UserBlindBoxHoldEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserBlindBoxHoldEntity::getBbId, orderBaseResVO.getBbId())
                    .eq(UserBlindBoxHoldEntity::getSerialNum, orderBaseResVO.getSerialNum())
                    .eq(UserBlindBoxHoldEntity::getStatus, 0)
                    .select();
            UserBlindBoxHoldEntity serviceOne = userBlindBoxHoldService.getOne(wrapper);
            LambdaUpdateWrapper<UserBlindBoxHoldEntity> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(UserBlindBoxHoldEntity::getId, serviceOne.getId())
                    .set(UserBlindBoxHoldEntity::getStatus, 2);
            userBlindBoxHoldService.update(lambdaUpdateWrapper);
            //先查自己是否曾经拥有过
            LambdaQueryWrapper<UserBlindBoxHoldEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper
                    .eq(UserBlindBoxHoldEntity::getBbId, orderBaseResVO.getBbId())
                    .eq(UserBlindBoxHoldEntity::getUserId, orderBaseResVO.getUserId())
                    .eq(UserBlindBoxHoldEntity::getSerialNum, orderBaseResVO.getSerialNum());
            UserBlindBoxHoldEntity one = userBlindBoxHoldService.getOne(lambdaQueryWrapper);
            if (Objects.isNull(one)) {
                UserBlindBoxHoldEntity userBlindBoxHoldEntity = new UserBlindBoxHoldEntity();
                userBlindBoxHoldEntity.setBbId(orderBaseResVO.getBbId());
                userBlindBoxHoldEntity.setSerialNum(orderBaseResVO.getSerialNum());
                userBlindBoxHoldEntity.setSourceType(0);
                userBlindBoxHoldEntity.setPurchasePrice(orderAmount);
                userBlindBoxHoldEntity.setUserId(orderBaseResVO.getUserId());
                userBlindBoxHoldService.save(userBlindBoxHoldEntity);
            } else {
                LambdaUpdateWrapper<UserBlindBoxHoldEntity> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(UserBlindBoxHoldEntity::getId, one.getId())
                        .set(UserBlindBoxHoldEntity::getStatus, 0);
                userBlindBoxHoldService.update(updateWrapper);
            }
            //钱包扣除手续费到账对方账户
            R<ConsignChargeVO> consignCharge = bacService.getConsignCharge();
            ConsignChargeVO chargeVO = OpsUtil.of(consignCharge)
                    .assertCode(CommonConstant.SUCCESS, e -> new FastException("获取费率信息异常！"))
                    .getData()
                    .get();

            BigDecimal charge = new BigDecimal(chargeVO.getChargeRate());
            //扣除费率
            BigDecimal chargeRate = charge.divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN);
            //扣除手续金额
            BigDecimal chargeAmount = orderAmount.multiply(chargeRate);
            //钱包到手金额
            BigDecimal earn = orderAmount.subtract(chargeAmount);
            Long oneUserId = serviceOne.getUserId();
            LambdaQueryWrapper<UserWalletEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserWalletEntity::getUserId, oneUserId)
                    .select();
            UserWalletEntity walletEntity = this.getOne(queryWrapper);
            LambdaUpdateWrapper<UserWalletEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserWalletEntity::getId, walletEntity.getId())
                    .set(UserWalletEntity::getBalance, walletEntity.getBalance().add(earn));
            this.update(updateWrapper);
            return true;
        }
        return true;
    }
}